package com.just_bean.core.bean;

import com.just_bean.core.aop.AopClz;
import com.just_bean.core.aop.CgLibClz;
import com.just_bean.core.aop.InterfaceClz;
import com.just_bean.core.exception.BeanInitException;
import com.just_bean.core.handler.AnnoHandler;
import com.just_bean.core.handler.JustMethodProxy;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public abstract class BaseBean<A extends Annotation> {

    public static Map<Class<? extends Annotation>, AnnoHandler> HANDLER_MAP;

    protected Class clz;
    private AopClz aopClz;

    public BaseBean(Class clz, A a) throws Exception {
        this.clz = clz;
        // 创建aop代理类
        if (clz.isInterface()) {
            this.aopClz = new InterfaceClz(clz);
        } else {
            this.aopClz = new CgLibClz(clz);
        }
        this.aopClz.setAopMap(this.aopMap(clz));
    }

    private Map<Method, List<JustMethodProxy>> aopMap(Class clz) throws Exception {
        Map<Method, List<JustMethodProxy>> map = new HashMap<>();

        for (Method method : clz.getMethods()) {
            Annotation[] annotationList = method.getAnnotations();
            List<JustMethodProxy> list = new ArrayList<>(annotationList.length);

            for (Annotation a : annotationList) {
                AnnoHandler handler = HANDLER_MAP.get(a.annotationType());
                if (handler == null) continue;
                JustMethodProxy proxy = handler.method(this.clz, method, a);
                list.add(proxy);
            }

            map.put(method, list);
        }
        return map;
    }

    // 判断是否符合条件的bean实例
    public abstract boolean check(Object... cond);

    // bean生命周期控制函数
    public abstract Object get() throws BeanInitException;

    // 创建实例
    protected Object create() throws BeanInitException {
        try {
            // 获取函数代理过的实例
            Object instance = aopClz.newInstance();
            // 对实例字段进行注入相关字段
            for (Field f : clz.getDeclaredFields()) {
                for (Annotation a : f.getAnnotations()) {
                    AnnoHandler handler = HANDLER_MAP.get(a.annotationType());
                    if (handler == null) continue;
                    f.setAccessible(true);
                    f.set(instance, handler.field(clz, f, a));
                    break;
                }
            }

            boolean isInitializing = Initializing.class.isAssignableFrom(this.clz);
            if (isInitializing) {
                ((Initializing) instance).initialize();
            }
            return instance;
        } catch (Exception e) {
            e.printStackTrace();
            throw new BeanInitException();
        }
    }

    public Class getClz() {
        return clz;
    }
}
